package 反射;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/*
    动态代理
        代理设计模式的原理:
            使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原 始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原 始对象上。
                 之前为大家讲解过代理机制的操作，属于静态代理，特征是代理类和目标 对象的类都是在编译期间确定下来，不利于程序的扩展。同时，每一个代 理类只能为一个接口服务，这样一来程序开发中必然产生过多的代理。最 好可以通过一个代理类完成全部的代理功能。
                动态代理是指客户通过代理类来调用其它对象的方法，并且是在程序运行时 根据需要动态创建目标类的代理对象。
                动态代理使用场合:
                    调试
                    远程方法调用
                动态代理相比于静态代理的优点：
                    抽象角色中（接口）声明的所有方法都被转移到调用处理器一个集中的方法中 处理，这样，我们可以更加灵活和统一的处理众多的方法。


      Java动态代理相关API
                Proxy ：专门完成代理的操作类，是所有动态代理类的父类。通过此类为一 个或多个接口动态地生成实现类。
                提供用于创建动态代理类和动态代理对象的静态方法
                      static Class<?>   getProxyClass(ClassLoader loader, Class<?>... interfaces)  创建 一个动态代理类所对应的Class对象
                      static Object   newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)  直接创建一个动态代理对象
      动态代理步骤
             1.创建一个实现接口InvocationHandler的类，它必须实现invoke方 法，以完成代理的具体操作。
               public Object invoke(Object theProxy, Method method, Object[] params)  throws Throwable{
                      try{
                          Object retval = method.invoke(targetObj, params);
                          // Print out the result
                          System.out.println(retval);
                          return retval;
                       }catch (Exception exc){}
                       }

 */
public class Proxy09 { //动态代理举例

    public static void main(String[] args) {
        //被代理类对象
        SuperMan superMan = new SuperMan();

        //proxyInstance:为代理类的对象
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);

        //当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("四川麻辣烫");

        System.out.println("**********************");

        NikeClothFactory nikeClothFactory = new NikeClothFactory();
        ClothFactory clothFactory = (ClothFactory)ProxyFactory.getProxyInstance(nikeClothFactory);
        clothFactory.produceCloth();
    }

}

interface Human{

    String getBelief();

    void eat(String food);

}

//被代表类
class SuperMan implements Human{

    @Override
    public String getBelief() {
        return "I believe I can Fly!";
    }

    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃" + food);
    }

}

/*
    实现动态代理,需要解决的问题:
        1、根据加载到内存中的被代理类,动态的创建一个代理类及其对象
        2、当通过代理类的对象调用方法a时,动态的去调用被代理类中同名的方法a
 */
class ProxyFactory{

    //调用此方法,返回一个代理类的对象  --> 解决问题1
    public static Object getProxyInstance(Object obj){ //obj为被代理类对象

        MyInvocationHandler handler = new MyInvocationHandler();

        handler.bind(obj);

        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
    }

}

class MyInvocationHandler implements InvocationHandler{

    private Object obj; //使用被代理类的对象进行赋值

    public void bind(Object obj){
        this.obj = obj;
    }

    /*
        当通过代理类的对象调用方法a时,就会自动的调用如下方法
        将被代理类要执行的方法a的功能声明在如下方法中
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        /*
            method:为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
            obj:被代理类的对象
         */
        Object returnValue = method.invoke(obj, args);

        //上述方法的返回值就作为当前类中的invoke()的返回值
        return returnValue;
    }
}
